<!DOCTYPE html>
<html lang="en">
<!-- <script src="/js/vconsole.min.js"></script> -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<script src="/js/vconsole.min.js"></script>
<title>图片像素化</title>

<head>
    <meta charset="utf-8">
    <script type="text/javascript">
        'use strict';
        var d = 10;
        var isTransing = false;

        var getFile = function (file) {
            var inputfile = file[0];
            fileToCanvas(inputfile);
            fileToImage(inputfile);
        }

        function fileToImage(file) {
            var reader = new FileReader();
            reader.readAsDataURL(file);//读取图像文件 result 为 DataURL, DataURL 可直接 赋值给 img.src
            reader.onload = function (event) {
                var img = document.getElementById("img").children[0];
                img.src = event.target.result;//base64
            }
        }

        function fileToCanvas(file) {
            var reader = new FileReader();
            reader.readAsDataURL(file);//读取图像文件 result 为 DataURL, DataURL 可直接 赋值给 img.src
            reader.onload = function (event) {
                var image = new Image();
                image.src = event.target.result;
                image.onload = function () {
                    var canvas = document.getElementById("canvas");
                    var imageCanvas = canvas.getContext("2d");
                    var ctx = canvas.getContext('2d');
                    var w = image.width;
                    var h = image.height;
                    var r = w < h ? w : h;
                    window.ctx = ctx;
                    window.image = image;
                    var nW = 300 / r * w;
                    var nH = 300 / r * h;
                    imageCanvas.drawImage(image, 0, 0, r, r, 0, 0, 300, 300);
                    canvasToImage(canvas);
                }
            }
        }
        window.onload = function () {
            var canvas = document.getElementById("canvas");
            canvas.addEventListener('click', setColors);
            // canvas.addEventListener('touch', setColors);
            var minerRateInput = document.getElementById("miner-rate");
            var transMethodInput = document.getElementById("trans-method");
            minerRateInput.addEventListener('touchmove', changeNum);
            transMethodInput.addEventListener('touchmove', changeNum);

            var u = navigator.userAgent, app = navigator.appVersion;
            console.log(u)
            var isMobile = !!u.match(/.*Mobile.*/) || !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
            if (isMobile) {
                document.getElementById('miner-rate').setAttribute('disabled', 'true');
                document.getElementById('trans-method').setAttribute('disabled', 'true');
            }
            if (window.screen.width < 800 && window.screen.height < 800) {
                console.log(window.screen.width, window,screen.height)
                document.getElementById('small-screen-ctrl').style.display = 'inline-block';
                document.getElementById('img').style.display = 'none';
            }
            // document.body.addEventListener('touchstart', function(){ });
            document.body.addEventListener('touchend', function() {});

            window.ctx = document.getElementById("canvas").getContext("2d");
            window.tranMethod = document.getElementById('trans-method');
            window.minerRate = document.getElementById('miner-rate');
        }

        function setColors(e) {
            var canvas = document.getElementById("canvas");
            var ctx = canvas.getContext("2d");
            window.e = e;
            // console.log(e.offsetX, e.offsetY);
            var x = e.offsetX;
            var y = e.offsetY;
            var lastVal = clg.value;
            colors.push(ctx.getImageData(x, y, 1, 1).data);
            clg.value = lastVal + '\n' + (x + ' ' + y + ' ' + JSON.stringify(ctx.getImageData(x, y, 1, 1).data));
            pic2Pixel()
        }

        function canvasToImage(canvas) {
            // var image = new Image();
            // image.src = canvas.toDataURL("image/png");//base64
            var img = document.getElementById("img").children[0];
            img.src = canvas.toDataURL("image/png")//base64
        }

        var colors = [];//[[0,0,0,255], [255,255,255,255]];
        var finalImages = [];

        // setTimeout(() => {
        //     console.log('go')
        //     pic2Pixel(document.getElementById("canvas").getContext("2d"), 3);
        // }, 20000)
        function pic2Pixel(ctx, idx) {
            if (isTransing) {
                console.log('正在转换中，勿重复点击')
                return;
            }
            if (colors.length == 0) {
                alert('1] 点击第一张图选取颜色；\n2] 滑动数字框来调整参数；\n3] 点击第二张图清除颜色；\n4] 长按第二张图保存图片；')
            }
            
            try {
                isTransing = true;
                let st1 = new Date().getTime();
                ctx = ctx || window.ctx;
                idx = idx || Number(window.tranMethod.value);
                d = Number(window.minerRate.value) || d;
                if (d < 1) d = 1;
                if (d > 300) d = 300;
                if (idx > 3) idx = 3;
                if (idx < 0) idx = 0;
                // console.log('idx', idx);
                // console.log('d', d)
                window.tranMethod.value = idx;
                window.minerRate.value = d;
                var colorSrc = ctx.getImageData(0, 0, 300, 300).data
                let st2 = new Date().getTime();
                let colorWidthDic = {};
                for (var i = 0; i < 300; i += d) {
                    for (var j = 0; j < 300; j += d) {
                        var minWidth = 10000000 * d * d;
                        var colorIdx = undefined;
                        for (var k = 0; k < colors.length; k++) {
                            var width = 10000000;
                            if (idx == 1) {
                                width = 0;
                            } else if (idx == 2) {
                            } else if (idx == 3) {
                            } else if (idx == 0) {
                            }
                            for (var _di = 0; _di < d; _di++) {
                                for (var _dj = 0; _dj < d; _dj++) {
                                    var y = i + _di;
                                    var x = j + _dj;
                                    if (y > 299) continue;
                                    if (x > 299) continue;
                                    var color = {
                                        '0': colorSrc[y * 4 * 300 + x * 4 + 0],
                                        '1': colorSrc[y * 4 * 300 + x * 4 + 1],
                                        '2': colorSrc[y * 4 * 300 + x * 4 + 2],
                                        '3': colorSrc[y * 4 * 300 + x * 4 + 3]
                                    };
                                    var r = color[0];
                                    var g = color[1];
                                    var b = color[2];
                                    var a = color[3];
                                    var _r = colors[k][0];
                                    var _g = colors[k][1];
                                    var _b = colors[k][2];
                                    var _a = colors[k][3];
                                    var _width = (r - _r) * (r - _r) + (g - _g) * (g - _g) + (b - _b) * (b - _b)
                                    if (idx == 1) {
                                        width += _width;//平滑过度算法
                                    } else if (idx == 2) {
                                        width = width < _width ? width : _width;//极值算法（有一个颜色最接近，就用那个）
                                    } else if (idx == 3) {
                                        _width = _width * (0.1 + 0.9 * (r + g + b) / 768) // 暗色调
                                        width = width < _width ? width : _width; // + 极值算法
                                    } else if (idx == 0) { // 超快速算法，越糊越快，只取一个
                                        _di = d;
                                        _dj = d;
                                        width = width < _width ? width : _width; // + 极值算法
                                    } else {
                                        width = width < _width ? width : _width;//极值算法（有一个颜色最接近，就用那个）
                                    }
                                }
                            }
                            if (width < minWidth) {
                                minWidth = width;
                                colorIdx = k;
                            }
                        }
                        for (var _di = 0; _di < d; _di++) {
                            for (var _dj = 0; _dj < d; _dj++) {
                                finalImages[i + _di] = finalImages[i + _di] || [];
                                finalImages[i + _di][j + _dj] = colors[colorIdx];
                            }
                        }
                    }
                }
                let st3 = new Date().getTime();
                var count = 0;
                var imageData = ctx.getImageData(0, 0, 300, 300)
                for (var i = 0; i < 300; i++) {
                    for (var j = 0; j < 300; j++) {
                        var x = i * 4 * 300 + 4 * j;
                        // ctx.rect(i, j, 1, 1);
                        // var color = finalImages[i][j];
                        // ctx.fillStyle = rgba(color[0], color[1], color[2]);
                        // ctx.fill();
                        // console.log(count++, i, j, rgba(color[0], color[1], color[2]))
                        imageData.data[x] = finalImages[i][j][0];
                        imageData.data[x + 1] = finalImages[i][j][1];
                        imageData.data[x + 2] = finalImages[i][j][2];
                        imageData.data[x + 3] = finalImages[i][j][3];

                    }
                }
                let st4 = new Date().getTime();
                console.log('st:', st2-st1, st3-st2,st4-st3)
                var ctx2 = document.getElementById("canvas2").getContext("2d");
                ctx2.putImageData(imageData, 0, 0, 0, 0, 300, 300)
                canvasToImage(document.getElementById("canvas2"));
                isTransing = false;
            } catch (err) {
                console.log(err);
                isTransing = false;
            }
        }
        function rgba(r, g, b, a) {
            var str = '0123456789ABCDEF'
            if (a == undefined) a = 255;
            var r1 = r / 16 | 0;
            var r2 = r % 16;
            var g1 = g / 16 | 0;
            var g2 = g % 16;
            var b1 = b / 16 | 0;
            var b2 = b % 16;
            var a1 = a / 16 | 0;
            var a2 = a % 16;
            return '#' + str[r1] + str[r2] + str[g1] + str[g2] + str[b1] + str[b2] + str[a1] + str[a2];
        }
        function toBegin() {
            document.getElementById('img').children[0].src = new Image();
            colors = [];
        }

        var lastTarX = undefined;
        var lastTarY = undefined;
        function changeNum(event, step) {
            step = step || 1;
            if (event.targetTouches.length == 2) {
                step = step * 5;
            }
            if (event.targetTouches.length == 3) {
                step = step * 10;
            }
            let accuracy = 1 / step;
            let newValue = new Number(event.target.value);
            // console.log(event.target.value)
            let _newValue;
            // console.log(newValue, newValue != undefined);
            let thisTarX = event.targetTouches[0].clientX;
            let thisTarY = event.targetTouches[0].clientY;
            if (!lastTarX) {
                lastTarX = thisTarX;
                lastTarY = thisTarY;
            } else {
                if (newValue != undefined && !isNaN(newValue)) {
                    // 防误触
                    if (lastTarY - thisTarY < 3 && thisTarY - lastTarY < 3) {
                        // 每移动10px改变1单位
                        if (thisTarX - lastTarX > 10) {
                            newValue = Math.round((newValue + step) * accuracy) / accuracy;
                            _newValue = newValue;
                            lastTarX = thisTarX;
                            lastTarY = thisTarY;
                        } else if (lastTarX - thisTarX > 10) {
                            newValue = Math.round((newValue - step) * accuracy) / accuracy;
                            _newValue = newValue;
                            lastTarX = thisTarX;
                            lastTarY = thisTarY;
                        }
                    } else {
                        lastTarX = thisTarX;
                        lastTarY = thisTarY;
                    }
                } else {
                    _newValue = 0;
                }
            }
            // console.log(_newValue)
            if (_newValue != undefined) {
                event.target.value = _newValue;
                pic2Pixel()
            }
        }
        var isSrcPicShow = true;
        function changeShowPic() {
            let srcImgBox = document.getElementById('canvas');
            let tarImgBox = document.getElementById('img');
            if (isSrcPicShow) {
                isSrcPicShow = false;
                srcImgBox.style.display = 'none';
                tarImgBox.style.display = 'inline-block';
            } else {
                isSrcPicShow = true;
                srcImgBox.style.display = 'inline-block';
                tarImgBox.style.display = 'none';
            }
        }
    </script>
</head>

<body ontouchstart="">
    <input id="true-img-ctrl" type="file" onchange="getFile(this.files)" style="display: none" />
    <input id="true-trans-ctrl" type="button" value="转换" onclick="pic2Pixel()" style="display: none" />
    <div class="contrl">
        <div class="img-ctrl" onclick="document.getElementById('true-img-ctrl').click()">
            <span>选择图片</span>
        </div>
        <div class="trans-ctrl" onclick="document.getElementById('true-trans-ctrl').click()">
            <span>开始转换</span>
        </div>
    </div>
    <div class="number-box">
        <div>
            <span>缩小率：</span>
            <input id="miner-rate" type="number" value="10"></input>
        </div>
        <div>
            <span>转换法：</span>
            <input id="trans-method" type="number" value="0"></input>
        </div>
    </div>
    <div id="small-screen-ctrl" onclick="changeShowPic()"></div>
    <div class="canvas-box">
        <canvas id="canvas" width='300' height='300'></canvas>
        <canvas id="canvas2" width='300' height='300' style="display:none"></canvas>
        <div id="img" onclick="toBegin()">
            <img src="" alt="显示图片" />
        </div>
    </div>
    <style>
        body {
            margin: 0;
        }

        * {
            -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
            -webkit-tap-highlight-color:transparent;
            touch-action: none;
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
            font-size: 0;
        }

        #small-screen-ctrl {
            display: none;
            position: fixed;
            top: 105px;
            right: -30px;
            width: 60px;
            height: 60px;
            background-color: rgba(0,50,0,.5);
            border-radius: 10px;
        }

        #__vconsole,
        #__vconsole * {
            font-size: 16px;
        }
        #img {
            display: inline-block;
        }

        #img>img {
            /* display: none; */
            border: 1px solid green;
            width: 300px;
            height: 300px;
            min-width: 300px;
            min-height: 300px;
        }

        input[type="button"],
        input[type="submit"],
        input[type="number"],
        input[type="reset"] {
            -webkit-appearance: none;
            width: 60vw;
            max-width: 200px;
        }

        textarea {
            display: none;
            -webkit-appearance: none;
        }

        body {
            text-align: center;
        }

        .contrl,
        .number-box {
            position: relative;
            display: inline-block;
            width: 100%;
            height: 80px;
            margin: 20px auto;
        }

        .contrl {
            margin-top: 5px;
        }

        .number-box {
            font-size: 20px;
            height: 70px;
            margin: 0 auto;
        }

        .number-box input {
            width: 60vw;
            height: 30px;
            max-width: 200px;
            line-height: 30px;
            box-sizing: border-box;
        }

        .contrl>div {
            display: inline-block;
            width: 45%;
            margin: 0 2%;
            line-height: 80px;
            text-align: center;
            cursor: pointer;
            border-radius: 10px;
            border: 2px solid black;
            box-sizing: border-box;
            box-shadow: rgba(0, 0, 0, 255) 3px 3px 1px 3px;
        }

        .contrl>div:hover {
            box-shadow: rgba(0, 0, 0, 255) 3px 3px 1px 3px;
        }

        .contrl>div:active {
            background-color: skyblue;
            box-shadow: rgba(0, 0, 0, 255) 0px 0px 0px 0px;
        }

        .contrl *,
        .number-box * {
            font-size: 20px;
        }

        .canvas-box {
            position: relative;
            display: inline;
            width: 100%;
            max-width: 1000px;
            text-align: center;
            margin: auto;
            margin-top: 10px;
            vertical-align: top;
        }

        .canvas-box>canvas {
            width: 300px;
            margin: auto;
            vertical-align: top;
        }

        #canvas {
            border: 1px solid red;
        }

        #canvas2 {
            border: 1px solid green;
        }

        textarea {
            margin-top: 10px;
            font-size: 16px;
            max-width: 100%;
            max-height: 50%;
        }
    </style>
    <textarea id="clg" rows="50" cols="100"></textarea>
</body>

</html>